using System;
using Wintellect.Threading.AsyncProgModel;

namespace FIFP.Common
{

    /// <summary>
    /// A specialisation of the <see cref="AsyncResult"/> class. It takes an <see cref="Action"/> delegate parameter that allows the called to pass in 
    /// the method that should be executed when the operation completes.
    /// </summary>
    /// <remarks>
    /// Further overloads with further parameters should be added as required, making use of additional Func delegates.
    /// </remarks>
    public sealed class AsyncTask : AsyncResult {
        private readonly Action _func;

        /// <summary>
        /// Initializes a new instance of the <see cref="AsyncTask"/> class.
        /// </summary>
        /// <param name="func">The func.</param>
        /// <param name="ac">The ac.</param>
        /// <param name="state">The state.</param>
        public AsyncTask(Action func, AsyncCallback ac, Object state)
            : base(ac, state) {
            _func = func;
            BeginInvokeOnWorkerThread();
        }

        protected override void OnCompleteOperation(IAsyncResult result) {
            _func();
        }

        /// <summary>
        /// Executes the specified Action delegate in a an asynchronous fashion, returning an <see cref="IAsyncResult"/> derivative.
        /// </summary>
        /// <param name="func">The func.</param>
        /// <returns>IAsyncResult derivative</returns>
        public static AsyncTask Run(Action func) {
            return Run(func, null, null);
        }

        /// <summary>
        /// Executes the specified Action delegate in a an asynchronous fashion, returning an <see cref="IAsyncResult"/> derivative.
        /// </summary>
        /// <param name="func">The func.</param>
        /// <param name="ac">The ac.</param>
        /// <param name="state">The state.</param>
        /// <returns></returns>
        public static AsyncTask Run(Action func, AsyncCallback ac, Object state) {
            return new AsyncTask(func,ac, state);
        }
    }

    /// <summary>
    /// A specialisation of the <see cref="AsyncResult{TResult}"/> class. It takes a type parameter of the expected return type
    /// and also takes a <see cref="Func{TResult}"/> parameter that allows the called to pass in the method that should be executed
    /// when the operation completes.
    /// </summary>
    /// <typeparam name="TResult">The type of the result.</typeparam>
    public sealed class AsyncTask<TResult> : AsyncResult<TResult> {

        private readonly Func<TResult> _func;

        /// <summary>
        /// Initializes a new instance of the <see cref="AsyncTask{TResul}"/> class.
        /// </summary>
        /// <param name="func">The func.</param>
        /// <param name="ac">The ac.</param>
        /// <param name="state">The state.</param>
        public AsyncTask(Func<TResult> func, AsyncCallback ac, Object state)
            : base(ac, state) {
            _func = func;
            BeginInvokeOnWorkerThread();
        }

        protected override TResult OnCompleteOperation(IAsyncResult result) {
            return _func();
        }

        /// <summary>
        /// Executes the specified Action delegate in a an asynchronous fashion, returning an <see cref="IAsyncResult"/> derivative.
        /// </summary>
        /// <param name="func">The func.</param>
        /// <returns></returns>
        public static AsyncTask<TResult> Run(Func<TResult> func) {
            return Run(func, null, null);
        }

        /// <summary>
        /// Executes the specified Action delegate in a an asynchronous fashion, returning an <see cref="IAsyncResult"/> derivative.
        /// </summary>
        /// <param name="func">The func.</param>
        /// <param name="ac">The ac.</param>
        /// <param name="state">The state.</param>
        /// <returns></returns>
        public static AsyncTask<TResult> Run(Func<TResult> func, AsyncCallback ac, Object state) {
            return new AsyncTask<TResult>(func, ac, state);
        }
    }

    /// <summary>
    /// A specialisation of the <see cref="AsyncResult{TResult}"/> class. It takes a type parameter of the expected return type
    /// and also takes a <see cref="Func{TResult}"/> parameter that allows the called to pass in the method that should be executed
    /// when the operation completes.
    /// </summary>
    /// <typeparam name="T"></typeparam>
    /// <typeparam name="TResult">The type of the result.</typeparam>
    public sealed class AsyncTask<T, TResult> : AsyncResult<TResult> {

        private readonly Func<T, TResult> _func;
        private readonly T _arg;

        /// <summary>
        /// Initializes a new instance of the <see cref="AsyncTask{T, TResult}"/> class.
        /// </summary>
        /// <param name="func">The func.</param>
        /// <param name="arg">The arg.</param>
        /// <param name="ac">The ac.</param>
        /// <param name="state">The state.</param>
        public AsyncTask(Func<T, TResult> func, T arg, AsyncCallback ac, Object state)
            : base(ac, state) {
            _func = func;
            _arg = arg;
            BeginInvokeOnWorkerThread();
        }

        protected override TResult OnCompleteOperation(IAsyncResult result) {
            return _func(_arg);
        }

        /// <summary>
        /// Executes the specified Action delegate in a an asynchronous fashion, returning an <see cref="IAsyncResult"/> derivative.
        /// </summary>
        /// <param name="func">The func.</param>
        /// <param name="arg">The arg.</param>
        /// <returns></returns>
        public static AsyncTask<T, TResult> Run(Func<T, TResult> func, T arg) {
            return Run(func, arg, null, null);
        }

        /// <summary>
        /// Executes the specified Action delegate in a an asynchronous fashion, returning an <see cref="IAsyncResult"/> derivative.
        /// </summary>
        /// <param name="func">The func.</param>
        /// <param name="arg">The arg.</param>
        /// <param name="ac">The ac.</param>
        /// <param name="state">The state.</param>
        /// <returns></returns>
        public static AsyncTask<T, TResult> Run(Func<T, TResult> func, T arg, AsyncCallback ac, Object state) {
            return new AsyncTask<T, TResult>(func, arg, ac, state);
        }
    }

    /// <summary>
    /// A specialisation of the <see cref="AsyncResult{TResult}"/> class. It takes a type parameter of the expected return type
    /// and also takes a <see cref="Func{TResult}"/> parameter that allows the called to pass in the method that should be executed
    /// when the operation completes.
    /// </summary>
    /// <typeparam name="T1">The type of the 1.</typeparam>
    /// <typeparam name="T2">The type of the 2.</typeparam>
    /// <typeparam name="TResult">The type of the result.</typeparam>
    public sealed class AsyncTask<T1, T2, TResult> : AsyncResult<TResult> {

        private readonly Func<T1, T2, TResult> _func;
        private readonly T1 _arg1;
        private readonly T2 _arg2;

        /// <summary>
        /// Initializes a new instance of the <see cref="AsyncTask{T1, T2, TResult}"/> class.
        /// </summary>
        /// <param name="func">The func.</param>
        /// <param name="arg1">The arg1.</param>
        /// <param name="arg2">The arg2.</param>
        /// <param name="ac">The ac.</param>
        /// <param name="state">The state.</param>
        public AsyncTask(Func<T1, T2, TResult> func, T1 arg1, T2 arg2, AsyncCallback ac, Object state)
            : base(ac, state) {
            _func = func;
            _arg1 = arg1;
            _arg2 = arg2;
            BeginInvokeOnWorkerThread();
        }

        protected override TResult OnCompleteOperation(IAsyncResult result) {
            return _func(_arg1, _arg2);
        }

        /// <summary>
        /// Executes the specified Action delegate in a an asynchronous fashion, returning an <see cref="IAsyncResult"/> derivative.
        /// </summary>
        /// <param name="func">The func.</param>
        /// <param name="arg1">The arg1.</param>
        /// <param name="arg2">The arg2.</param>
        /// <returns></returns>
        public static AsyncTask<T1, T2, TResult> Run(Func<T1, T2, TResult> func, T1 arg1, T2 arg2) {
            return Run(func, arg1, arg2, null, null);
        }

        /// <summary>
        /// Executes the specified Action delegate in a an asynchronous fashion, returning an <see cref="IAsyncResult"/> derivative.
        /// </summary>
        /// <param name="func">The func.</param>
        /// <param name="arg1">The arg1.</param>
        /// <param name="arg2">The arg2.</param>
        /// <param name="ac">The ac.</param>
        /// <param name="state">The state.</param>
        /// <returns></returns>
        public static AsyncTask<T1, T2, TResult> Run(Func<T1, T2, TResult> func, T1 arg1, T2 arg2, AsyncCallback ac, Object state) {
            return new AsyncTask<T1, T2, TResult>(func, arg1, arg2, ac, state);
        }
    }

    /// <summary>
    /// A specialisation of the <see cref="AsyncResult{TResult}"/> class. It takes a type parameter of the expected return type
    /// and also takes a <see cref="Func{TResult}"/> parameter that allows the called to pass in the method that should be executed
    /// when the operation completes.
    /// </summary>
    /// <typeparam name="T1">The type of the 1.</typeparam>
    /// <typeparam name="T2">The type of the 2.</typeparam>
    /// <typeparam name="T3">The type of the 3.</typeparam>
    /// <typeparam name="TResult">The type of the result.</typeparam>
    public sealed class AsyncTask<T1, T2, T3, TResult> : AsyncResult<TResult> {

        private readonly Func<T1, T2, T3, TResult> _func;
        private readonly T1 _arg1;
        private readonly T2 _arg2;
        private readonly T3 _arg3;

        /// <summary>
        /// Initializes a new instance of the <see cref="AsyncTask{T1, T2, T3, TResult}"/> class.
        /// </summary>
        /// <param name="func">The func.</param>
        /// <param name="arg1">The arg1.</param>
        /// <param name="arg2">The arg2.</param>
        /// <param name="arg3">The arg3.</param>
        /// <param name="ac">The ac.</param>
        /// <param name="state">The state.</param>
        public AsyncTask(Func<T1, T2, T3, TResult> func, T1 arg1, T2 arg2, T3 arg3, AsyncCallback ac, Object state)
            : base(ac, state) {
            _func = func;
            _arg1 = arg1;
            _arg2 = arg2;
            _arg3 = arg3;
            BeginInvokeOnWorkerThread();
        }

        protected override TResult OnCompleteOperation(IAsyncResult result) {
            return _func(_arg1, _arg2, _arg3);
        }

        /// <summary>
        /// Executes the specified Action delegate in a an asynchronous fashion, returning an <see cref="IAsyncResult"/> derivative.
        /// </summary>
        /// <param name="func">The func.</param>
        /// <param name="arg1">The arg1.</param>
        /// <param name="arg2">The arg2.</param>
        /// <param name="arg3">The arg3.</param>
        /// <returns></returns>
        public static AsyncTask<T1, T2, T3, TResult> Run(Func<T1, T2, T3, TResult> func, T1 arg1, T2 arg2, T3 arg3) {
            return Run(func, arg1, arg2, arg3, null, null);
        }

        /// <summary>
        /// Executes the specified Action delegate in a an asynchronous fashion, returning an <see cref="IAsyncResult"/> derivative.
        /// </summary>
        /// <param name="func">The func.</param>
        /// <param name="arg1">The arg1.</param>
        /// <param name="arg2">The arg2.</param>
        /// <param name="arg3">The arg3.</param>
        /// <param name="ac">The ac.</param>
        /// <param name="state">The state.</param>
        /// <returns></returns>
        public static AsyncTask<T1, T2, T3, TResult> Run(Func<T1, T2, T3, TResult> func, T1 arg1, T2 arg2, T3 arg3, AsyncCallback ac, Object state) {
            return new AsyncTask<T1, T2, T3, TResult>(func, arg1, arg2, arg3, ac, state);
        }
    }

    /// <summary>
    /// A specialisation of the <see cref="AsyncResult{TResult}"/> class. It takes a type parameter of the expected return type
    /// and also takes a <see cref="Func{TResult}"/> parameter that allows the called to pass in the method that should be executed
    /// when the operation completes.
    /// </summary>
    /// <typeparam name="T1">The type of the 1.</typeparam>
    /// <typeparam name="T2">The type of the 2.</typeparam>
    /// <typeparam name="T3">The type of the 3.</typeparam>
    /// <typeparam name="T4">The type of the 4.</typeparam>
    /// <typeparam name="TResult">The type of the result.</typeparam>
    public sealed class AsyncTask<T1, T2, T3, T4, TResult> : AsyncResult<TResult> {

        private readonly Func<T1, T2, T3, T4, TResult> _func;
        private readonly T1 _arg1;
        private readonly T2 _arg2;
        private readonly T3 _arg3;
        private readonly T4 _arg4;

        /// <summary>
        /// Initializes a new instance of the <see cref="AsyncTask{T1, T2, T3, T4, TResult}"/> class.
        /// </summary>
        /// <param name="func">The func.</param>
        /// <param name="arg1">The arg1.</param>
        /// <param name="arg2">The arg2.</param>
        /// <param name="arg3">The arg3.</param>
        /// <param name="arg4">The arg4.</param>
        /// <param name="ac">The ac.</param>
        /// <param name="state">The state.</param>
        public AsyncTask(Func<T1, T2, T3, T4, TResult> func, T1 arg1, T2 arg2, T3 arg3, T4 arg4, AsyncCallback ac, Object state)
            : base(ac, state) {
            _func = func;
            _arg1 = arg1;
            _arg2 = arg2;
            _arg3 = arg3;
            _arg4 = arg4;
            BeginInvokeOnWorkerThread();
        }

        protected override TResult OnCompleteOperation(IAsyncResult result) {
            return _func(_arg1, _arg2, _arg3, _arg4);
        }

        /// <summary>
        /// Executes the specified Action delegate in a an asynchronous fashion, returning an <see cref="IAsyncResult"/> derivative.
        /// </summary>
        /// <param name="func">The func.</param>
        /// <param name="arg1">The arg1.</param>
        /// <param name="arg2">The arg2.</param>
        /// <param name="arg3">The arg3.</param>
        /// <param name="arg4">The arg4.</param>
        /// <returns></returns>
        public static AsyncTask<T1, T2, T3, T4, TResult> Run(Func<T1, T2, T3, T4, TResult> func, T1 arg1, T2 arg2, T3 arg3, T4 arg4) {
            return Run(func, arg1, arg2, arg3, arg4, null, null);
        }

        /// <summary>
        /// Executes the specified Action delegate in a an asynchronous fashion, returning an <see cref="IAsyncResult"/> derivative.
        /// </summary>
        /// <param name="func">The func.</param>
        /// <param name="arg1">The arg1.</param>
        /// <param name="arg2">The arg2.</param>
        /// <param name="arg3">The arg3.</param>
        /// <param name="arg4">The arg4.</param>
        /// <param name="ac">The ac.</param>
        /// <param name="state">The state.</param>
        /// <returns></returns>
        public static AsyncTask<T1, T2, T3, T4, TResult> Run(Func<T1, T2, T3, T4, TResult> func, T1 arg1, T2 arg2, T3 arg3, T4 arg4, AsyncCallback ac, Object state) {
            return new AsyncTask<T1, T2, T3, T4, TResult>(func, arg1, arg2, arg3, arg4, ac, state);
        }
    }

    /// <summary>
    /// A specialisation of the <see cref="AsyncResult{TResult}"/> class. It takes a type parameter of the expected return type
    /// and also takes a <see cref="Func{TResult}"/> parameter that allows the called to pass in the method that should be executed
    /// when the operation completes.
    /// </summary>
    /// <typeparam name="T1">The type of the 1.</typeparam>
    /// <typeparam name="T2">The type of the 2.</typeparam>
    /// <typeparam name="T3">The type of the 3.</typeparam>
    /// <typeparam name="T4">The type of the 4.</typeparam>
    /// <typeparam name="T5">The type of the 5.</typeparam>
    /// <typeparam name="TResult">The type of the result.</typeparam>
    public sealed class AsyncTask<T1, T2, T3, T4, T5, TResult> : AsyncResult<TResult> {

        private readonly Func<T1, T2, T3, T4, T5, TResult> _func;
        private readonly T1 _arg1;
        private readonly T2 _arg2;
        private readonly T3 _arg3;
        private readonly T4 _arg4;
        private readonly T5 _arg5;

        /// <summary>
        /// Initializes a new instance of the <see cref="AsyncTask{T1, T2, T3, T4, T5, TResult}"/> class.
        /// </summary>
        /// <param name="func">The func.</param>
        /// <param name="arg1">The arg1.</param>
        /// <param name="arg2">The arg2.</param>
        /// <param name="arg3">The arg3.</param>
        /// <param name="arg4">The arg4.</param>
        /// <param name="arg5">The arg5.</param>
        /// <param name="ac">The ac.</param>
        /// <param name="state">The state.</param>
        public AsyncTask(Func<T1, T2, T3, T4, T5, TResult> func, T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, AsyncCallback ac, Object state)
            : base(ac, state) {
            _func = func;
            _arg1 = arg1;
            _arg2 = arg2;
            _arg3 = arg3;
            _arg4 = arg4;
            _arg5 = arg5;
            BeginInvokeOnWorkerThread();
        }

        protected override TResult OnCompleteOperation(IAsyncResult result) {
            return _func(_arg1, _arg2, _arg3, _arg4, _arg5);
        }

        /// <summary>
        /// Executes the specified Action delegate in a an asynchronous fashion, returning an <see cref="IAsyncResult"/> derivative.
        /// </summary>
        /// <param name="func">The func.</param>
        /// <param name="arg1">The arg1.</param>
        /// <param name="arg2">The arg2.</param>
        /// <param name="arg3">The arg3.</param>
        /// <param name="arg4">The arg4.</param>
        /// <param name="arg5">The arg5.</param>
        /// <returns></returns>
        public static AsyncTask<T1, T2, T3, T4, T5, TResult> Run(Func<T1, T2, T3, T4, T5, TResult> func, T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5) {
            return Run(func, arg1, arg2, arg3, arg4, arg5, null, null);
        }

        /// <summary>
        /// Executes the specified Action delegate in a an asynchronous fashion, returning an <see cref="IAsyncResult"/> derivative.
        /// </summary>
        /// <param name="func">The func.</param>
        /// <param name="arg1">The arg1.</param>
        /// <param name="arg2">The arg2.</param>
        /// <param name="arg3">The arg3.</param>
        /// <param name="arg4">The arg4.</param>
        /// <param name="arg5">The arg5.</param>
        /// <param name="ac">The ac.</param>
        /// <param name="state">The state.</param>
        /// <returns></returns>
        public static AsyncTask<T1, T2, T3, T4, T5, TResult> Run(Func<T1, T2, T3, T4, T5, TResult> func, T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, AsyncCallback ac, Object state) {
            return new AsyncTask<T1, T2, T3, T4, T5, TResult>(func, arg1, arg2, arg3, arg4, arg5, ac, state);
        }
    }
}